package com.xli.ui.module.framemodulerole.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.CacheManager;
import com.alicp.jetcache.anno.CacheConsts;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.template.QuickConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xli.ui.module.framemodulerole.entity.FrameModuleRole;
import com.xli.ui.module.framemodulerole.entity.ModuleRoleCache;
import com.xli.ui.module.framemodulerole.mapper.FrameModuleRoleMapper;
import com.xli.ui.module.framemodulerole.mapper.IModuleRoleCacheMapper;
import com.xli.ui.module.framemodulerole.service.IFrameModuleRoleService;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Validated
@Service
public class FrameModuleRoleServiceImpl extends ServiceImpl<FrameModuleRoleMapper, FrameModuleRole> implements IFrameModuleRoleService {

    private final Lock lock = new ReentrantLock();

    @Autowired
    CacheManager cacheManager;

    Cache<Long, List<ModuleRoleCache>> moduleRoleCache;

    @PostConstruct
    public void init() {
        lock.lock();
        try {
            QuickConfig qc = QuickConfig.newBuilder("frame_module_role:list:")
                    .expire(Duration.ofSeconds(CacheConsts.DEFAULT_EXPIRE))
                    .cacheType(CacheType.BOTH)
                    .syncLocal(true)
                    .build();
            moduleRoleCache = cacheManager.getOrCreateCache(qc);

            List<FrameModuleRole> frameModuleRoleList = this.findList(new QueryWrapper<>());
            List<ModuleRoleCache> cacheList = IModuleRoleCacheMapper.INSTANCE.toCacheList(frameModuleRoleList);

            // 根据角色分组
            Map<Long, List<ModuleRoleCache>> groupRoleList = cacheList.stream()
                    .collect(Collectors.groupingBy(ModuleRoleCache::getRole_id));
            groupRoleList.forEach((roleId, moduleRoleCacheList) -> {
                moduleRoleCache.put(roleId, moduleRoleCacheList);
            });

            // 根据模块分组
            Map<Long, List<ModuleRoleCache>> groupModuleList = cacheList.stream()
                    .collect(Collectors.groupingBy(ModuleRoleCache::getModule_id));
            groupModuleList.forEach((moduleId, moduleUserCacheList) -> {
                moduleRoleCache.put(moduleId, moduleUserCacheList);
            });
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean insert(FrameModuleRole frameModuleRole) {
        lock.lock();
        try {
            boolean result = this.save(frameModuleRole);
            if (result) {
                List<ModuleRoleCache> cacheList = moduleRoleCache.get(frameModuleRole.getRole_id());
                if (cacheList == null) {
                    cacheList = new ArrayList<>();
                }
                cacheList.add(IModuleRoleCacheMapper.INSTANCE.toCacheEntity(frameModuleRole));
                moduleRoleCache.put(frameModuleRole.getRole_id(), cacheList);

                //更新模块分组
                cacheList = moduleRoleCache.get(frameModuleRole.getModule_id());
                if (cacheList == null) {
                    cacheList = new ArrayList<>();
                }
                cacheList.add(IModuleRoleCacheMapper.INSTANCE.toCacheEntity(frameModuleRole));
                moduleRoleCache.put(frameModuleRole.getModule_id(), cacheList);
            }
            return result;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean insert(Long moduleId, List<String> roleIds) {
        for (String roleId : roleIds) {
            FrameModuleRole frameModuleRole = FrameModuleRole.builder()
                    .id(IdUtil.getSnowflakeNextId())
                    .module_id(moduleId)
                    .role_id(Long.valueOf(roleId))
                    .build();
            insert(frameModuleRole);
        }
        return true;
    }

    @Override
    public boolean delete(Long id) {
        lock.lock();
        try {
            FrameModuleRole frameModuleRole = this.find(id);
            if (frameModuleRole != null) {
                boolean result = this.removeById(id);
                if (result) {
                    List<ModuleRoleCache> cacheList = moduleRoleCache.get(frameModuleRole.getRole_id());
                    if (cacheList == null) {
                        cacheList = new ArrayList<>();
                    }
                    cacheList.removeIf(moduleUserCache -> moduleUserCache.getId().equals(id));
                    moduleRoleCache.put(frameModuleRole.getRole_id(), cacheList);

                    //更新模块分组
                    cacheList = moduleRoleCache.get(frameModuleRole.getModule_id());
                    if (cacheList == null) {
                        cacheList = new ArrayList<>();
                    }
                    cacheList.removeIf(moduleUserCache -> moduleUserCache.getId().equals(id));
                    moduleRoleCache.put(frameModuleRole.getModule_id(), cacheList);
                }
                return result;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean delete(Long moduleId, List<String> roleIds) {
        for (String roleId : roleIds) {
            FrameModuleRole frameModuleRole = find(moduleId, Long.valueOf(roleId));
            if (frameModuleRole != null) {
                this.delete(frameModuleRole.getId());
            }
        }
        return true;
    }

    @Override
    public FrameModuleRole find(Long id) {
        return this.getById(id);
    }

    @Override
    public FrameModuleRole find(Long moduleId, Long roleId) {
        List<FrameModuleRole> frameModuleRoleList = findModuleRoleListByModuleId(moduleId);
        for (FrameModuleRole frameModuleRole : frameModuleRoleList) {
            if (frameModuleRole.getRole_id().equals(roleId)) {
                return frameModuleRole;
            }
        }
        return null;
    }

    @Override
    public List<FrameModuleRole> findList(QueryWrapper<FrameModuleRole> qw) {
        return this.list(qw);
    }

    @Override
    public long findCount(QueryWrapper<FrameModuleRole> qw) {
        return this.count(qw);
    }

    @Override
    public Page<FrameModuleRole> findList(QueryWrapper<FrameModuleRole> qw, long current, long size) {
        return this.page(new Page<>(current, size), qw);
    }

    @Override
    public List<FrameModuleRole> findModuleRoleListByRoleId(Long roleId) {
        List<ModuleRoleCache> cacheList = moduleRoleCache.get(roleId);
        if (cacheList == null) {
            cacheList = new ArrayList<>();
        }
        return IModuleRoleCacheMapper.INSTANCE.toEntityList(cacheList);
    }

    @Override
    public List<FrameModuleRole> findModuleRoleListByModuleId(Long moduleId) {
        List<ModuleRoleCache> cacheList = moduleRoleCache.get(moduleId);
        if (cacheList == null) {
            cacheList = new ArrayList<>();
        }
        return IModuleRoleCacheMapper.INSTANCE.toEntityList(cacheList);
    }
}
